<?php
/**
 * 服务器之间的传输器
 */

if (!defined('IN_APP')) die('Hacking attempt');

class transport {
	/**
	 * 脚本执行时间 -1表示采用PHP默认值
	 */
	private $time_limit = -1;

	/**
	 * 连接超时 -1：PHP默认值
	 */
	private $content_timeout = -1;

	/**
	 * 连接后限定多少秒超时 -1表示采用PHP默认值，仅采用CURL库时开启
	 */
	private $stream_timeout = -1;

	/**
	 * 是否使用 curl连接, false表示采用fsockopen连接
	 */
	private $use_curl = false;

	/**
	 * 构造函数
	 */
	public function __construct($time_limit = -1, $connect_timeout = -1, $stream_timeout = -1, $use_curl = false) {
		$this->time_limit = $time_limit;
		$this->connect_timeout = $connect_timeout;
		$this->stream_timeout = $stream_timeout;
		$this->use_curl = $use_curl;
	}

	/**
	 * 请求远程服务器
	 */
	public function request($url, $params = '', $method = 'POST', $my_header = '') {
		$fsock_exists = function_exists('fsockopen');
		$curl_exists = function_exists('curl_init');

		if (!fsock_exists && !$curl_exists) {
			die('No method available!');
		}

		if (!url) {
			die('Invalid URL!');
		}

		/* -1就不再手动设置，使用默认值*/
		if ($this->time_limit > -1) {
			set_time_limit($this->time_limit);
		}
		
		if (!in_array($method, array('GET', 'POST'))) {
			die('Invalid method!');
		}

		$response = '';
		$temp_str = '';

		/* 格式化将要发送的参数*/
		if ($param && is_array($param)) {
			foreach ($param AS $key => $value) {
				$temp_str .= '&' . $key . '=' . $value;
			}
			$params = preg_replace('/^&/', '', $temp_str);
		}

		/* 如果fsockopen存在，并且用户没有指定curl，则用use_socket函数*/
		if ($fsock_exists && !$this->use_curl) {
			$response = $this->use_socket($url, $params, $method, $my_header);
		} elseif ($curl_exists) {
			$response = $this->use_curl($url, $params, $method, $my_header);
		}

		/* 空响应或者传输过程中发生错误，程序将返回false*/
		if (!$response) {
			return false;
		}
		return $response;
	}

	/**
	 * 是用 fsockopen库进行连接
	 */
	public function use_socket($url, $parames, $method, $my_header) {
		$query = '';
		$auth = '';
		$content_type = '';
		$content_length = '';
		$request_body = '';
		$request = '';
		$http_response = '';
		$temp_str = '';
		$error = '';
		$errstr = '';
		$crlf = $this->generate_crlf();

		if ($methos == 'GET') {
			$query = $parames ? '?'.$parames : '';
		} else {
			$request_body = $parames;
			$content_type = 'Content-Type: application/x-www-form-urlencoded' . $crlf;
			$content_length = 'Content-Length: ' . strlen($request_body) . $crlf . $crlf;
		}

		$url_parts = $this->parse_raw_url($url);
		$path = $url_parts['path'] . $query;

		if (!empty($url_parts['user'])) {
			$auth = 'Authorization: Basic ' . base64_encode($user_parts['user'] . ':' . $user_parts['pass']) . $crlf;
		}

		/* 格式化自定义头部信息*/
		if ($my_header && is_array($my_header)) {
			foreach ($my_header AS $key => $value) {
				$temp_str .= $key . ': ' . $value . $crlf;
			}
			$my_header = $temp_str;
		}

		/* 构造http请求头*/
		$request = $method . ' ' . $path . ' ' . 'HTTP/1.0' . $crlf
				. 'HOST: ' . $url_parts['host'] . $crlf
				. $auth
				. $my_header
				. $content_type
				. $content_length
				. $request_body;

		if ($this->content_timeout > -1) {
			$fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr, $this->content_timeout);
		} else {
			$fp = @fsockopen($url_parts['host'], $url_parts['port'], $error, $errstr);
		}

		/* 打开失败*/
		if (!fp) {
			return false;
		}

		/* 写入失败*/
		if (!@fwrite($fp, $request)) {
			return false;
		}

		while (!feof($fp)) {
			$http_response .= fgets($fp);
		}

		if (!$http_response) {
			return false;
		}

		/* 分割响应头和响应体*/
		$separator = '/\r\n\r\n|\n\n|\r\r/';
		list($http_header, $http_body) = preg_split($separator, $http_response, 2);

		$http_response = array('header' => $http_header, 'body' => $http_body);
		@fclose($fp);
		return $http_response;
	}

	/**
	 * 使用 CURL进行连接
	 */
	public function use_curl($url, $params, $method, $my_header) {
		/* 开始一个新回话*/
		$curl_session = curl_init();

		/* 基本设置 */
		curl_setopt($curl_session, CURLOPT_FORBID_REUSE, true); // 处理完后，关闭连接，释放资源
		curl_setopt($curl_session, CURLOPT_HEADER, true);//结果中包含头部信息
		curl_setopt($curl_session, CURLOPT_RETURNTRANSFER, true);//把结果返回，而非直接输出
		curl_setopt($curl_session, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//采用1.0版的HTTP协议

		$url_parts = $this->parse_raw_url($url);

		/* 设置验证码策略*/
		if (!empty($url_parts['user'])) {
			$auth = $url_parts['use'] . ':' . $curl_parts['pass'];
			curl_setopt($curl_session, CURLOPT_USERPWD, $auth);
			curl_setopt($curl_session, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
		}
		$header = array();

		/* 设置主机*/
		$header[] = 'HOST: ' . $url_parts['host'];

		/* 格式化自定义头部信息*/
		if ($my_header && is_array($my_header)) {
			foreach ($my_header AS $key => $value) {
				$header[] = $key . ': ' . $value;
			}
		}

		if ($method == 'GET']) {
			curl_setopt($curl_session, CURLOPT_HTTPGET, true);
			$url .= $params ? '?' . $params : '';
		} else {
			curl_setopt($curl_session, CURLOPT_POST, true);
			$header[] = 'Content-Type: application/x-www-form-urlencoded';
			$header[] = 'Content-Length: ' . strlen($params);
			curl_setopt($curl_session, CURLOPT_POSTFIELDS, $params);
		}

		/* 设置请求地址 */
		curl_setopt($curl_session, CURLOPT_URL, $url);

		/* 设置头部信息 */
		curl_setopt($curl_session, CURLOPT_HTTPHEADER, $header);

		if ($this->connect_timeout > -1) {
			curl_setopt($curl_session, CURLOPT_CONNECTTIMEOUT, $this->connect_timeout);
		}

		if ($this->stream_timeout > -1) {
			curl_setopt($curl_session, CURLOPT_TIMEOUT, $this->stream_timeout);
		}

		/* 发送请求 */
		$http_response = curl_exec($curl_session);

		if (curl_errno($curl_session) != 0) {
			return false;
		}

		$separator = '/\r\n\r\n|\n\n|\r\r/';
		list($http_header, $http_body) = preg_split($separator, $http_response, 2);

		$http_response = array('header' => $http_header,//肯定有值
							   'body'   => $http_body); //可能为空

		curl_close($curl_session);
		return $http_response;
	}

	/**
	 * 分析URL parse_url返回数组
	 */
	public function parse_raw_url($raw_url) {
		$retval = array();
		$raw_url = (string)$raw_url;

		if (strpos($raw_url, '://') === false) {
			$raw_url = 'http://' . $raw_url;
		}

		$retval = parse_url($raw_url);
		if (!isset($retval['path'])) {
			$retval['path'] = '/';
		}

		if (!isset($retval['port'])) {
			$retval['port'] = '80';
		}
		return $retval;
	}

	/**
	 * 得到当前操作系统的换行符
	 */
	public function generate_crlf() {
		$crlf = '';

		if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
			$crlf = "\r\n";
		} elseif (strtoupper(substr(PHP_OS, 0, 3)) === 'MAC') {
			$crlf = "\r";
		} else {
			$crlf = "\n";
		}
		return $crlf;
	}
}
